﻿using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.RelyingParty;
using StudyTracker.Domain.Entities;
using StudyTracker.Web.Models.Authentication;

namespace StudyTracker.Web.Controllers
{
	public partial class AuthenticationController : Controller
    {
		private static readonly OpenIdRelyingParty OpenId = new OpenIdRelyingParty();

		[ChildActionOnly]
		public virtual ActionResult LoginMenu()
		{
			Student currentStudent = null;

			if (User != null && User.Identity.IsAuthenticated)
			{
				currentStudent = Student.Find(x => x.AuthenticationIdentifier == User.Identity.Name).SingleOrDefault();
			}

			return PartialView(new LoginMenuModel(currentStudent));
		}

		public virtual ActionResult Logout()
		{
			FormsAuthentication.SignOut();
			return RedirectToAction(MVC.Home.Index());
		}

		public virtual ActionResult Login()
		{
			if (User != null && User.Identity.IsAuthenticated)
			{
				return RedirectToAction(MVC.Data.DailyGraph());
			}

			return View();
		}

		public virtual ActionResult Authenticate(string openIdIdentifier)
		{
			IAuthenticationResponse response = OpenId.GetResponse();
			if (response == null)
			{
				// Stage 2: user submitting Identifier
				Identifier id;
				if (Identifier.TryParse(openIdIdentifier, out id))
				{
					try
					{
						IAuthenticationRequest request = OpenId.CreateRequest(openIdIdentifier);

						var fetchRequest = new FetchRequest();
						fetchRequest.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
						request.AddExtension(fetchRequest);

						return request.RedirectingResponse.AsActionResult();
					}
					catch (ProtocolException ex)
					{
						TempData["Message"] = ex.Message;
						return RedirectToAction(MVC.Home.Index());
					}
				}
				else
				{
					TempData["Message"] = "Invalid identifier";
					return RedirectToAction(MVC.Home.Index());
				}
			}
			else
			{
				// Stage 3: OpenID Provider sending assertion response
				switch (response.Status)
				{
					case AuthenticationStatus.Authenticated:
						FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);

						FetchResponse fetchResponse = response.GetExtension<FetchResponse>();
						string email = string.Empty;
						if (fetchResponse != null)
						{
							email = fetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email);
						}

						// if this user doesn't exist, create it
						Student student = Student.Find(x => x.AuthenticationIdentifier == response.ClaimedIdentifier.ToString()).SingleOrDefault();
						if (student == null)
						{
							Student.Save(new Student(response.ClaimedIdentifier, email));
						}

						TempData["Message"] = string.Format("Welcome, {0}.", email);
						return RedirectToAction(MVC.Data.DailyGraph());

					case AuthenticationStatus.Canceled:
						TempData["Message"] = "Canceled at provider";
						return RedirectToAction(MVC.Home.Index());
					
					case AuthenticationStatus.Failed:
						TempData["Message"] = response.Exception.Message;
						return RedirectToAction(MVC.Home.Index());
				}
			}
			return new EmptyResult();
		}
	}
}
